from typing import Optional, Dict, Any, List
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi import HTTPException, status

from modules.system.models.dict import DictType
from modules.system.models.dict_item import Dictionary
from modules.system.schemas.dict_schemas import DictTypeCreate, DictTypeUpdate
from modules.system.params.dict_params import DictTypeQuery
from modules.system.curd.dict_curd import dict_type_dao
from utils.query_builder import build_select_stmt
from core.pagination import paging_data, _CustomPageParams


class DictService:
    @staticmethod
    async def get_type_by_id(db: AsyncSession, type_id: int) -> Optional[DictType]:
        return await dict_type_dao.get_by_id(db, type_id)

    @staticmethod
    async def get_type_by_code(db: AsyncSession, type_code: str) -> Optional[DictType]:
        return await dict_type_dao.get_by_code(db, type_code)

    @staticmethod
    async def get_type_by_name(db: AsyncSession, type_name: str) -> Optional[DictType]:
        return await dict_type_dao.get_by_name(db, type_name)

    @staticmethod
    async def get_types_with_pagination(db: AsyncSession, query_params: DictTypeQuery) -> Dict[str, Any]:
        # 统一查询构建与分页封装
        stmt = build_select_stmt(
            DictType,
            query_params,
            text_like_fields={"type_code", "type_name", "type_desc"},
            keyword_fields={"type_code", "type_name", "type_desc"},
        )
        stmt = stmt.order_by(DictType.id.asc())
        params = _CustomPageParams(page=query_params.page, size=query_params.size)
        page_data = await paging_data(db, stmt, params=params)
        page_data["pages"] = page_data.get("total_pages", 0)
        page_data.pop("links", None)
        return page_data

    @staticmethod
    async def create_type(db: AsyncSession, payload: DictTypeCreate) -> DictType:
        # 唯一性校验
        if await DictService.get_type_by_code(db, payload.type_code):
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="类型编码已存在")
        if await DictService.get_type_by_name(db, payload.type_name):
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="类型名称已存在")

        obj = await dict_type_dao.create(db, payload)
        await db.commit()
        await db.refresh(obj)
        return obj

    @staticmethod
    async def update_type(db: AsyncSession, type_id: int, payload: DictTypeUpdate) -> DictType:
        obj = await DictService.get_type_by_id(db, type_id)
        if not obj:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="字典类型不存在")

        # 变更唯一性校验
        if payload.type_code and payload.type_code != obj.type_code:
            if await DictService.get_type_by_code(db, payload.type_code):
                raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="类型编码已存在")
        if payload.type_name and payload.type_name != obj.type_name:
            if await DictService.get_type_by_name(db, payload.type_name):
                raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="类型名称已存在")

        # 使用仓储更新
        obj = await dict_type_dao.update(db, type_id, payload)
        await db.commit()
        if obj:
            await db.refresh(obj)
        return obj

    @staticmethod
    async def delete_type(db: AsyncSession, type_id: int) -> None:
        obj = await DictService.get_type_by_id(db, type_id)
        if not obj:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="字典类型不存在")
        await dict_type_dao.delete(db, type_id)
        await db.commit()

    # 批量获取字典项，并按类型分组返回，供前端缓存使用
    @staticmethod
    async def get_items_grouped_by_types(db: AsyncSession, type_codes: Optional[List[str]] = None) -> Dict[str, List[Dictionary]]:
        return await dict_type_dao.get_items_grouped_by_types(db, type_codes)